;/***************************************************
;		版权声明
;
;	本操作系统名为：MINE
;	该操作系统未经授权不得以盈利或非盈利为目的进行开发，
;	只允许个人学习以及公开交流使用
;
;	代码最终所有权及解释权归田宇所有；
;
;	本模块作者：	田宇
;	EMail:		345538255@qq.com
;	
;	相对于上一版加入FAT—12
;***************************************************/

	org	0x7c00	

BaseOfStack	equ	0x7c00

;这里的BaseOfLoader和OffsetOfLoader组成了Loader程序的起始地址
;这个组合必须经过实模式的地址变换公式才能生成物理地址
;即BaseOfLoader << 4 + OffsetOfLoader = 0x10000
BaseOfLoader	equ	0x1000
OffsetOfLoader	equ	0x00

;/***************************************************
;	2879+--------+
;		|        |
;		| 数据区  |
;		|        |
;		|		 |
;		|		 |
;       +--------+
;       |		 |
;		| 根目录  |
;	  18+--------+
;	    |		 |
;	  10| FAT2	 |
;	    +--------+
;	   9|		 |
;		| FAT1   |
;	   1+--------+
;		|		 |
;		|引导扇区 |
;	   0+--------+
;
;***************************************************/
;定义了根目录中根目录的扇区数
;(BPB_RootEntCnt * 32 + BPB_BytesPerSec - 1) / BPB_BytesPerSec = (224 * 32 + 512- 1) / 512 = 14
RootDirSectors	equ	14
;定义了根目录的起始扇区号
;保留扇区数 + FAT表扇区数 * FAT表份数 = 1 + 9 * 2 = 19
SectorNumOfRootDirStart	equ	19
;代表了FAT1表的起始扇区号，因为FAT1前只有一个保留扇区，且它的编号是0，故FAT1起始扇区号为1
SectorNumOfFAT1Start	equ	1
;用于平衡文件（目录）的起始簇号与数据区起始簇号的差值。19 - 2 = 17
SectorBalance	equ	17	

	jmp	short Label_Start
	nop
	BS_OEMName	db	'MINEboot'
	BPB_BytesPerSec	dw	512		;每扇区字节数
	BPB_SecPerClus	db	1		;每簇扇区数，文件系统以簇为最小单位，本书为512
	BPB_RsvdSecCnt	dw	1		;保留扇区数，本书为1
	BPB_NumFATs	db	2			;FAT表的份数（为了备份），本书为2
	BPB_RootEntCnt	dw	224		;根目录可容纳的目录数，本书为224
	BPB_TotSec16	dw	2880	;总扇区数，本书为2880
	BPB_Media	db	0xf0		;介质描述符，本书为0xF0
	BPB_FATSz16	dw	9			;每FAT扇区数，本书为9
	BPB_SecPerTrk	dw	18		;每磁道扇区数，本书为18
	BPB_NumHeads	dw	2		;磁头数，本书为2
	BPB_HiddSec	dd	0			;隐藏扇区数，本书为0
	BPB_TotSec32	dd	0		;如果BPB_TotSet16为0，则由这个记录扇区数，本书为0
	BS_DrvNum	db	0			;int 13h的驱动器号，本书为0
	BS_Reserved1	db	0		;为使用，本书为0
	BS_BootSig	db	0x29		;扩展引导标记
	BS_VolID	dd	0			;卷序列号,，本书为0
	BS_VolLab	db	'boot loader';卷标，本书为'boot loader'
	BS_FileSysType	db	'FAT12   ';文件系统类型

Label_Start:

	mov	ax,	cs
	mov	ds,	ax
	mov	es,	ax
	mov	ss,	ax
	mov	sp,	BaseOfStack

;=======	clear screen

	mov	ax,	0600h
	mov	bx,	0700h
	mov	cx,	0
	mov	dx,	0184fh
	int	10h

;=======	set focus

	mov	ax,	0200h
	mov	bx,	0000h
	mov	dx,	0000h
	int	10h

;=======	display on screen : Start Booting......

	mov	ax,	1301h
	mov	bx,	000fh
	mov	dx,	0000h
	mov	cx,	10
	push	ax
	mov	ax,	ds
	mov	es,	ax
	pop	ax
	mov	bp,	StartBootMessage
	int	10h

;=======	reset floppy

	xor	ah,	ah
	xor	dl,	dl
	int	13h

;=======	search loader.bin
;RootDirSizeForLoop	dw	RootDirSectors
;SectorNo		dw	0
;Odd			db	0

	mov	word	[SectorNo],	SectorNumOfRootDirStart

Lable_Search_In_Root_Dir_Begin:

	cmp	word	[RootDirSizeForLoop],	0
	jz	Label_No_LoaderBin					;为0跳转
	dec	word	[RootDirSizeForLoop]	
	mov	ax,	00h
	mov	es,	ax								;es,bx为目标缓冲区地址
	mov	bx,	8000h
	mov	ax,	[SectorNo]						;待读入磁盘的起始扇区号
	mov	cl,	1								;读入的扇区数量
	call	Func_ReadOneSector
	mov	si,	LoaderFileName
	mov	di,	8000h
	cld
	mov	dx,	10h
	
Label_Search_For_LoaderBin:

	cmp	dx,	0
	jz	Label_Goto_Next_Sector_In_Root_Dir
	dec	dx
	mov	cx,	11								;文件名长度

Label_Cmp_FileName:

	cmp	cx,	0
	jz	Label_FileName_Found
	dec	cx
	lodsb	
	cmp	al,	byte	[es:di]					;存的文件名，可以理解为一个字符数组，es为基址，di为偏移量
	jz	Label_Go_On
	jmp	Label_Different

Label_Go_On:
	
	inc	di									;增减di，一个字符一个的比
	jmp	Label_Cmp_FileName

Label_Different:

	and	di,	0ffe0h
	add	di,	20h
	mov	si,	LoaderFileName
	jmp	Label_Search_For_LoaderBin

Label_Goto_Next_Sector_In_Root_Dir:
	
	add	word	[SectorNo],	1
	jmp	Lable_Search_In_Root_Dir_Begin
	
;=======	display on screen : ERROR:No LOADER Found

Label_No_LoaderBin:

	mov	ax,	1301h
	mov	bx,	008ch
	mov	dx,	0100h
	mov	cx,	21
	push	ax
	mov	ax,	ds
	mov	es,	ax
	pop	ax
	mov	bp,	NoLoaderMessage
	int	10h
	jmp	$

;=======	found loader.bin name in root director struct

Label_FileName_Found:

	mov	ax,	RootDirSectors
	and	di,	0ffe0h
	add	di,	01ah
	mov	cx,	word	[es:di]
	push	cx
	add	cx,	ax
	add	cx,	SectorBalance
	mov	ax,	BaseOfLoader
	mov	es,	ax
	mov	bx,	OffsetOfLoader
	mov	ax,	cx

Label_Go_On_Loading_File:
	push	ax
	push	bx
	mov	ah,	0eh
	mov	al,	'.'
	mov	bl,	0fh
	int	10h
	pop	bx
	pop	ax

	mov	cl,	1
	call	Func_ReadOneSector
	pop	ax
	call	Func_GetFATEntry
	cmp	ax,	0fffh
	jz	Label_File_Loaded
	push	ax
	mov	dx,	RootDirSectors
	add	ax,	dx
	add	ax,	SectorBalance
	add	bx,	[BPB_BytesPerSec]
	jmp	Label_Go_On_Loading_File

Label_File_Loaded:
	
	jmp	$

;=======	read one sector from floppy
;AX=待读取的磁盘起始扇区号
;CL=读入的扇区数量
;EX：BS目标缓冲区起始地址

Func_ReadOneSector:
	
	push	bp
	mov	bp,	sp
	sub	esp,	2
	mov	byte	[bp - 2],	cl
	push	bx
	mov	bl,	[BPB_SecPerTrk]
	div	bl
	inc	ah
	mov	cl,	ah	;目标磁道内起始扇区号（从1开始）
	mov	dh,	al
	shr	al,	1
	mov	ch,	al
	and	dh,	1
	pop	bx
	mov	dl,	[BS_DrvNum]
Label_Go_On_Reading:
	mov	ah,	2
	mov	al,	byte	[bp - 2]
	int	13h
	jc	Label_Go_On_Reading
	add	esp,	2
	pop	bp
	ret

;=======	get FAT Entry

Func_GetFATEntry:

	push	es
	push	bx
	push	ax
	mov	ax,	00
	mov	es,	ax
	pop	ax
	mov	byte	[Odd],	0
	mov	bx,	3
	mul	bx
	mov	bx,	2
	div	bx
	cmp	dx,	0
	jz	Label_Even
	mov	byte	[Odd],	1

Label_Even:

	xor	dx,	dx
	mov	bx,	[BPB_BytesPerSec]
	div	bx
	push	dx
	mov	bx,	8000h
	add	ax,	SectorNumOfFAT1Start
	mov	cl,	2
	call	Func_ReadOneSector
	
	pop	dx
	add	bx,	dx
	mov	ax,	[es:bx]
	cmp	byte	[Odd],	1
	jnz	Label_Even_2
	shr	ax,	4

Label_Even_2:
	and	ax,	0fffh
	pop	bx
	pop	es
	ret

;=======	tmp variable

RootDirSizeForLoop	dw	RootDirSectors
SectorNo		dw	0
Odd			db	0

;=======	display messages

StartBootMessage:	db	"Start Boot"
NoLoaderMessage:	db	"ERROR:No LOADER Found"
LoaderFileName:		db	"LOADER  BIN",0

;=======	fill zero until whole sector

	times	510 - ($ - $$)	db	0
	dw	0xaa55	;结束标志

